﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Aim2.Screen {
    class Bar {
        public int Height { get; set; }
        public int Depth { get; set; }

        public Bar(int h, int d) {
            Height = h;
            Depth = d;
        }
    }

    public enum BarFormula {
        Fast,
        Slow,
        FastReverse,
        SlowReverse
    }

    public class Bars {
        private Texture2D barTexture;
        FloatTransition transitionBarsSize;
        private int numberOfBarsLayers;
        public bool BarSizeFormula { get; set; }
        const int barSize = 6;
        public int FactorOfBars { get; set; }

        List<Bar> barsHeights = new List<Bar>();

        static List<Color> barsColors = new List<Color>();

        float barSizeFactor = 1f;
        public BarFormula BarFormula { get; set; }
        bool allFaded;
        public bool Fading { get; set; }

        public int NumberOfBarsLayers {
            get {
                return numberOfBarsLayers;
            }
            set {
                numberOfBarsLayers = value;
                FactorOfBars = (int)Math.Pow(2, numberOfBarsLayers - 1);
                BuildBarsColors();
                SetBars();
            }
        }

        public Bars() {
            NumberOfBarsLayers = 3;
            BarFormula = BarFormula.Slow;
        }

        public void LoadContent(GraphicsDevice graphicsDevice) {
            barTexture = new Texture2D(graphicsDevice, 1, 1, false, SurfaceFormat.Color);
            barTexture.SetData<Color>(new Color[] { new Color(255, 153, 0, 255) });
        }

        public void Draw(SpriteBatch spriteBatch, GraphicsDevice graphicsDevice) {

            spriteBatch.Begin();
            foreach (Bar t in barsHeights) {
                int barSizeTemp;
                if (BarSizeFormula)
                    barSizeTemp = (int)(barSize * (barSizeFactor * (t.Depth + 1)));
                else
                    barSizeTemp = (int)(barSize * (barSizeFactor + (numberOfBarsLayers - t.Depth + 1)));
                Rectangle destRect = new Rectangle(0, t.Height, graphicsDevice.Viewport.Width, barSizeTemp);
                spriteBatch.Draw(barTexture,
                     destRect,
                     null,
                     barsColors[t.Depth]);
            }
            spriteBatch.End();
        }

        public bool Update(float elapsed, float timeElapsed, float timeBetweenBeats, float timeBetweenBeatsHelper, int screenHeight) {
            float percentage;

            if (transitionBarsSize != null) {
                transitionBarsSize.Update(elapsed);
                barSizeFactor = transitionBarsSize.CurrentValue;
                if (transitionBarsSize.IsOver())
                    transitionBarsSize = null;
            }

            allFaded = true;
            foreach (Bar b in barsHeights) {
                if (Fading && barsColors[b.Depth].A > 0) {
                    Color c = barsColors[b.Depth];
                    int alpha = c.A;
                    alpha -= 2;
                    if (alpha <= 0) {
                        alpha = 0;
                    }
                    else
                        allFaded = false;
                    c.A = (byte)alpha;
                    barsColors[b.Depth] = c;
                }
                switch (BarFormula) {
                    case BarFormula.Fast:
                        percentage = (float)((timeElapsed / timeBetweenBeats) / Math.Pow(2, b.Depth)) % 1;
                        b.Height = (int)(screenHeight * percentage);
                        break;
                    case BarFormula.Slow:
                        percentage = timeElapsed / timeBetweenBeatsHelper;
                        b.Height = (int)(percentage * (NumberOfBarsLayers - b.Depth + 1) * screenHeight / 2);
                        if (b.Height > screenHeight && b.Depth == numberOfBarsLayers - 1)
                            timeElapsed = 0f;
                        break;
                    default:
                        throw new Exception("Formule pas encore implémentée");
                }
            }
            return allFaded && Fading;
        }

        public void SetBars() {
            this.barsHeights.Clear();
            for (int i = 0; i < NumberOfBarsLayers; i++)
                this.barsHeights.Add(new Bar(0, i));
        }

        public void RemoveBars() {
            this.barsHeights.Clear();
        }

        public void InitTransitionBarsSize(float t, float v) {
            transitionBarsSize = new FloatTransition(t, v, barSizeFactor);
        }

        public void BuildBarsColors() {
            barsColors.Clear();
            for (int i = 0; i < NumberOfBarsLayers; i++) {
                float alpha = (NumberOfBarsLayers - i);
                alpha = alpha / (float)NumberOfBarsLayers;
                alpha = alpha * 255f;
                barsColors.Add(new Color(255, 255, 255, (int)alpha));
            }
        }

        public void Dispose() {
            if (barTexture != null) {
                barTexture.Dispose();
                barTexture = null;
            }
        }
    }
}
